pp108 : UDDI Connector

UDDI Connector

This topic describes the APIs for UDDI connectors.

UDDI Connector API

  • SetProfile (UDDI)

    Note: For UDDI Service Group, the payload validation must not be enabled.

UDDI Interceptor

UDDI connector provides a mechanism, UDDI Interceptor, to manipulate SOAP requests passing from the Process Platform environment to an external Web service. This mechanism is needed as the underlying backend system imposes specific requirements on how to interact with it.
A UDDI Interceptor is a Java class that enables manipulating SOAP requests passing from the Process Platform environment to an external Web service, by implementing the interfacecom.eibus.applicationconnector.uddi.Interceptor. UDDI interceptor intercepts the request before it goes to the external service from Process Platform and similarly intercepts the response (either success or failure).
This interface, com.eibus.applicationconnector.uddi.Interceptor, contains the following Web service operations:

public void initialize(int methodImplementation);
public void onRequest(int request);
public void onResponse(int response);
public void onSOAPFault(int soapFault); 

Within the UDDI connector, the role of the Interceptor in the execution flow is as follows:

  1. The UDDI connector checks an incoming request to ascertain whether an interceptor has been defined in the LDAP Web service operation implementation.
  2. If an interceptor is defined, an interceptor object is created using the default constructor.
  3. The Web service operation onRequest is called on the Interceptor object. At this point the request is manipulated, if required.
  4. The request is sent to the external service and a response is received subsequently.
  5. If a SOAPFault is returned, the Web service operation, onSOAPFault , is called on the Interceptor object. Else, the Web service operation, onResponse, is called on the Interceptor object.

Exception Handling

If an exception is thrown inside the interceptor code, UDDI connector will throw anInterceptorExceptionthat contains information about the exception thrown.

Definition

The UDDI connector uses the information from the Web service operation implementation (in LDAP) to call the external Web service. An example of such an implementation is:

<implementation type="Invoke">
    <serviceuri>http://d-sxcsrv.nl.dap.philips.com:1080/sap/bc/soap/rfc</serviceuri>
    <soapaction>http://www.sap.com/Z_PORTAL_GET_CUSTOMER_ADDRES</soapaction>
    <authenticationType>Anonymous</authenticationType>
</implementation>

In case an interceptor is required for a certain Web service operation, it is specified in the Web service operation implementation as shown below:

<implementation type="Invoke">
    <serviceuri>http://d-sxcsrv.nl.dap.philips.com:1080/sap/bc/soap/rfc</serviceuri>
    <soapaction>http://www.sap.com/Z_PORTAL_GET_CUSTOMER_ADDRES</soapaction>
    <authenticationType>Anonymous</authenticationType>
    <interceptor>
        <class>com.cordys.coe.mycomp.MyInterceptor</class>
    </interceptor>
</implementation>

Sample Implementation

The configuration for the sample Web service operation implementation, NamespaceInterceptor, can be added manually inside the <interceptor> tag as shown below. On creation of Interceptor object, the Web service operation implementation is provided to the Interceptor. The Interceptor uses the configuration details to initialize itself. In case the sample implementation is to be used for the external service, prefix and namespace have to be manually added within the <interceptor> tag.

 <implementation type='Invoke'>
 <serviceuri>http://d-sxcsrv.nl.dap.philips.com:1080/sap/bc/soap/rfc</serviceuri>
 <soapaction>http://www.sap.com/Z_PORTAL_GET_CUSTOMER_ADDRES</soapaction>
 <authenticationType>Anonymous</authenticationType>
 <interceptor <class>com.cordys.myproject.uddi.NamespaceInterceptor</class>
   <prefix>ns1</prefix>
   <namespace>urn:sap-com:document:sap:rfc:functions</namespace>
 </interceptor>
</implementation> 

The Namespaceinterceptor implementation can replace the name passed from the Process Platform environment into the namespace required by the external Web service. It can also add a prefix before the Web service operation name in the SOAP request. Such a prefix is required in case of SAP backend. The implementation is provided below:

package com.eibus.applicationconnector.uddi.interceptor;
import com.eibus.applicationconnector.uddi.Interceptor;
import com.eibus.util.logger.CordysLogger;
import com.eibus.util.logger.Severity;
import com.eibus.xml.nom.Document;
import com.eibus.xml.nom.Find;
import com.eibus.xml.nom.Node;
import com.eibus.xml.nom.XMLException;
import com.eibus.xml.xpath.NodeSet;
import com.eibus.xml.xpath.XPath;
import com.eibus.xml.xpath.XPathMetaInfo;
/**
* Implementation of the Interceptor interface.
* The purpose of this interceptor is to change the namespace for the
* Web service operation name that goes to the external service.
* With this interceptor, you can create
* unique namespaces at Process Platform side and at external Web service.
* This is required when two different external Web services are being
* accessed that use the same namespace (e.g.
* two identical SAP systems). To distinguish the two systems at Process Platform side
* Process Platform side 2 namespace can be used.
* <p>
* The configuration of this interceptor consists of two parts:
* <li>the namespace to be used to the external system</li>
* <li>if the XML node with the Web service operation name requires a namespace prefix, and the value
of that prefix, if the namespace
prefix is required.
* It is expected that there is no prefix yet./<li>
* <p>
* The interceptor will adapt the request as follows:
* <p><code>
* BAPI_FLIGHT_GETLIST
* xmlns="cordys_namespace">
* /<code><p>
* into
* <p><code>
* prefix_from_interceptor_config:BAPI_FLIGHT_GETLIST
* xmlns:prefix_from_interceptor_config="namespace_from_interceptor_config">
* </code><p>
* The response is manipulated in the opposite way.
* <p>
* The interceptor is specified in the Web service operation implementation which is
* stored in LDAP. This is done in a node <interceptor>, as follows:
* <p>
* <code>
* implementation type="Invoke">
*  <serviceuri>http://d-sxcsrv.nl.mycomp.com:1080/sap/bc/soap/rfc</serviceuri>
*  <soapaction>http://www.sap.com/Z_PORTAL_GET_CUSTOMER_ADDRES</soapaction>
*  <authenticationType>Anonymous</authenticationType>
*  <interceptor>
*   <class>com.cordys.project.mycomp.uddi.MyInterceptor?</class>
*   <prefix>ns1</prefix>
*   <namespace>urn:sap-com:document:sap:rfc:functions</namespace>
*  </interceptor>
* </implementation>
* </code>
 p>
* For the example above:
* <code>
* ns1:BAPI_FLIGHT_GETLIST xmlns:ns1="urn:sap-com:document:sap:rfc:functions">
* </code>
*
* @author hbank
*
*/
public class NamespaceInterceptor implements Interceptor
{
   private final static CordysLogger uddiLogger = CordysLogger.getCordysLogger(NamespaceInterceptor.class);
   private final static String TAG_Envelope = "Envelope";
   private final static String TAG_Body = "Body";
   private final static String TAG_INTERCEPTOR = "interceptor";
   private final static String TAG_PREFIX = "prefix";
   private final static String TAG_NAMESPACE = "namespace";
   private final static String MATCH_PREFIX= <"implementation><" + TAG_INTERCEPTOR
+ ">" + TAG_PREFIX + ">";
   private final static String MATCH_NAMESPACE = <"implementation><" + TAG_INTERCEPTOR
+ ">" + TAG_NAMESPACE + ">";
// store the values from the Web service operation implementation
private String m_prefix = null;
private String m_namespace = null;
// save value of xmlns in case it is overwritten
private String m_saveXmlns = null;
/**
* Initialize the Interceptor
* @param methodImplementation the implementation of the Web service operation, as stored in LDAP
*/
public void initialize(int methodImplementation)
{
  m_prefix = Node.getDataWithDefault(Find.firstMatch(methodImplementation, MATCH_PREFIX),
null);
  m_namespace = Node.getDataWithDefault(Find.firstMatch(methodImplementation, MATCH_NAMESPACE),
null);
}
/**
* Add prefix before tag name in Web service operation node
* Add corresponding namespace
*/
public void onRequest(int request)
{
   if (uddiLogger.isDebugEnabled())
{
   uddiLogger.debug("Interceptor: request to process:\n" + Node.writeToString(request,
true));
}
// find the node with the method (SOAP:Envelope/SOAP:Body/.
int methodNode = getNodeToUpdate(request);
if ( methodNode == 0 )
{
   uddiLogger.log(Severity.ERROR, "Did not find ./Envelope/Body in the request\n"
+
   Node.writeToString(request, true));
   return;
}
// replace data
String methodName = Node.getName(methodNode);
// add prefix
if ( m_prefix != null )
{
   // what is namespace to set?
   String namespace = m_namespace;
   if ( namespace == null )
   {
     namespace = Node.getNamespaceURI(methodNode);
   }
     methodName = m_prefix + ":" + methodName;
     Node.setName(methodNode, methodName);
     // remove any pre-existing namespace
     m_saveXmlns = Node.getAttribute(methodNode, "xmlns");
     Node.removeAttribute(methodNode, "xmlns");
     // set namespace
     String attributeName = "xmlns:" + m_prefix;
     Node.setAttribute(methodNode, attributeName, namespace);
   }
  else
  {
     // set namespace
     m_saveXmlns = Node.getAttribute(methodNode, "xmlns");
     String attributeName = "xmlns";
     Node.setAttribute(methodNode, attributeName, m_namespace);
  }
  if (uddiLogger.isDebugEnabled())
  {
  uddiLogger.debug("Interceptor: processed request:\n" + Node.writeToString(request,
true));
  }
 }
 /**
 * Drop prefix before tag name in Web service operation node
 * Restore namespace
 */
 public void onResponse(int response)
 {
    if (uddiLogger.isDebugEnabled())
    {
        uddiLogger.debug("Interceptor: response to process:\n" + Node.writeToString(response,
true));
    }
       // find the node with the method (SOAP:Envelope/SOAP:Body/.
       int methodNode = getNodeToUpdate(response);
       if ( methodNode == 0 )
    {
       uddiLogger.log(Severity.ERROR, "Did not find ./Envelope/Body in the response\n"
+
       Node.writeToString(response, true));
       return;
    }
    // replace data
    String methodName = Node.getName(methodNode);
    // drop prefix
   if ( m_prefix != null )
   {
        // find the prefix
       int posColon = methodName.indexOf(":");
       if ( posColon > 0 )
       {
       String prefix = methodName.substring(0, posColon);
       String method = methodName.substring(posColon+1);
       // update the node name, without prefix
       Node.setName(methodNode, method);
       // remove the namespace with prefix
       String attributeName = "xmlns:" + prefix;
       Node.removeAttribute(methodNode, attributeName);
      // reset the original namespace
      if ( m_saveXmlns != null )
       {
       Node.setAttribute(methodNode, "xmlns", m_saveXmlns);
       }
    }
  }
  else
  {
   String attributeName = "xmlns";
   Node.removeAttribute(methodNode, attributeName);
   if ( m_saveXmlns != null )
  {
    Node.setAttribute(methodNode, attributeName, m_saveXmlns);
  }
 }
 if (uddiLogger.isDebugEnabled())
 {
 uddiLogger.debug("Interceptor: processed response:\n" + Node.writeToString(response,
true));
 }
}
/**
* Process any SOAP fault
* Don't manipulate. Return null means that the original exception is passed to the
caller.
*/
public void onSOAPFault(int soapFault)
{
  // no special action required
}
/**
* Find the method node.
* Usually the method node is request.firstChild.firstChild.
* The Web service operation searches for SOAP:Envelope/SOAP:Body. While searching the namespace
* prefix is ignored because it can be any prefix (SOAP, soap, SOAP-ENV etc.)
* @param request
* @return
*/
private int getNodeToUpdate(int request)
  {
    // <SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
    //  <SOAP:Body>
    //   BAPI_FLIGHT_GETLIST xmlns="urn:sap-com:document:sap:rfc:functions">
    //    <AIRLINE>LH</AIRLINE><FLIGHT_LIST><item><AIRLINEID></AIRLINEID><AIRLINE></AIRLINE><CONNECTID></CONNECTID><FLIGHTDATE></FLIGHTDATE><AIRPORTFR></AIRPORTFR><CITYFROM></CITYFROM><AIRPORTTO></AIRPORTTO><CITYTO></CITYTO><DEPTIME></DEPTIME><ARRTIME></ARRTIME><ARRDATE></ARRDATE><PRICE>0</PRICE><CURR></CURR><CURR_ISO></CURR_ISO>/<item>/<FLIGHT_LIST><MAX_ROWS>0</MAX_ROWS>
    //   </BAPI_FLIGHT_GETLIST>
    //  </SOAP:Body>
    // </SOAP:Envelope>
    XPath xpathBody = new XPath("//soap:Envelope/soap:Body/*");
    XPathMetaInfo xm= new XPathMetaInfo();
    xm.addNamespaceBinding("soap","http://schemas.xmlsoap.org/soap/envelope/");
    NodeSet nodes = xpathBody.selectNodeSet(request,xm);
    int nodArr[]=nodes.getElementNodes();
    return nodArr.length > 0 ? nodArr[0]: 0;
  }
  /**
  * Test method
  * @param args
  */
  public static void main(String[] args)
  {
      String requestXML =
         "SOAP:Envelope xmlns:SOAP=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+
          "SOAP:Body>" +
           "BAPI_FLIGHT_GETLIST xmlns=\"http://cordys.schemas.com/coe/project\">"
+
             "<AIRLINE>LH/AIRLINE>" +
             "<FLIGHT_LIST>" +
             "<item>" +
              "<AIRLINEID></AIRLINEID>" +
              "<AIRLINE></AIRLINE>" +
              "<CONNECTID></CONNECTID>" +
              "FLIGHTDATE>/FLIGHTDATE>" +
              "<AIRPORTFR></AIRPORTFR>" +
              "<CITYFROM></CITYFROM>" +
              "<AIRPORTTO></AIRPORTTO>" +
              "<CITYTO></CITYTO>" +
            "</item>" +
           "</FLIGHT_LIST>" +
          "<MAX_ROWS>0</MAX_ROWS>" +
         "</BAPI_FLIGHT_GETLIST>" +
        "</SOAP:Body>" +
       "</SOAP:Envelope>";
     String methodImplementation =
      "implementation type=\"Invoke\">" +
        "<serviceuri>http://d-sxcsrv.nl.project.com:1080/sap/bc/soap/rfc"
+
        "<soapaction>http://www.sap.com/Z_PORTAL_GET_CUSTOMER_ADDRES"
+
        "<authenticationType>Anonymous/<authenticationType>" +
        "  <interceptor>" +
          "   <class>com.eibus.applicationconnector.uddi.intercepter.NamespaceInterceptor"
+
          "<prefix>ns1</prefix>" +
          "<namespace>urn:sap-com:document:sap:rfc:functions</namespace>" +
        "</interceptor>" +
      "</implementation>";
    if ( args.length != 2 )
    {
     System.out.println("Usage: NamespaceInterceptor file with method implementation>
file with SOAP request>");
     return;
    }
    try
    {
      Document doc = new Document();
      int implementation = doc.parseString(methodImplementation);
      int request = doc.parseString(requestXML);
      Interceptor i = new NamespaceInterceptor();
      i.initialize(implementation);
      System.out.println(Node.writeToString(request, true));
      i.onRequest(request);
      System.out.println(Node.writeToString(request, true));
      i.onResponse(request);
      System.out.println(Node.writeToString(request, true));
      doc.getHandle(); // prevent GC of document
    }
    catch (XMLException e)
    {
     // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (Throwable t)
    {
    // TODO Auto-generated catch block
    t.printStackTrace();
    }
  }
}